package cn.crawler.app.crown.modules.services.impl.result;

import cn.crawler.app.crown.commons.util.DateUtil;
import cn.crawler.app.crown.commons.websocket.action.ResultAction;
import cn.crawler.app.crown.modules.models.CrownConfig;
import cn.crawler.app.crown.modules.models.CrownMatch;
import cn.crawler.app.crown.modules.models.constant.CrownConstant;
import cn.crawler.app.crown.modules.services.CrownConfigService;
import cn.crawler.app.crown.modules.services.CrownMatchService;
import cn.crawler.app.crown.modules.services.result.MatchResultService;
import cn.crawler.app.sys.modules.services.SysParamService;
import cn.crawler.framework.base.service.BaseServiceImpl;
import cn.crawler.framework.util.Result;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSONArray;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Dao;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import java.util.Map;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@IocBean(args = {"refer:dao"})
@Service(interfaceClass = MatchResultService.class)
public class MatchResultServiceImpl extends BaseServiceImpl<CrownMatch> implements MatchResultService {

    public MatchResultServiceImpl(Dao dao) {
        super(dao);
    }

    private static final Log log = Logs.get();

    @Inject
    private RedisService redisService;
    @Inject
    private CrownMatchService matchService;
    @Inject
    @Reference(retries = 0, timeout = 500000)
    private CrownConfigService crownConfigService;
    @Inject
    @Reference
    private SysParamService sysParamService;


    private static final Pattern MATCH_COMPILE = Pattern.compile("gdata = Array\\((.*?)\\);");


    @Override
    public void crawler(CrownMatch match, CrownConfig crownConfig) {
        String mid = match.getMid();
        JSONArray jsonArray = this.getData(match, crownConfig);
        if (jsonArray == null) {
            this.sendEmail(match);
            return;
        }
        // 皇冠原数据mid发生变化，重新请求
        else if ("Y".equals(jsonArray.getString(8)) && jsonArray.size() < 74) {
            // mid减1
            String newMid = String.valueOf(Integer.parseInt(mid) - 1);
            match.setMid(newMid);
            log.info("赛果爬取失败.mid减一再次发送请求,mid：" + newMid);
            jsonArray = this.getData(match, crownConfig);
            if (jsonArray == null) {
                this.sendEmail(match);
                return;
            }
            // mid加1
            else if ("Y".equals(jsonArray.getString(8)) && jsonArray.size() < 74) {
                newMid = String.valueOf(Integer.parseInt(mid) + 1);
                match.setMid(newMid);
                log.info("赛果爬取失败.mid加一再次发送请求,mid：" + newMid);
                jsonArray = this.getData(match, crownConfig);
                // 发送邮件
                if (jsonArray == null) {
                    this.sendEmail(match);
                    return;
                }
            }
        }
        // 保存最初的mid，crawler与rebuild的mid保持一致
        match.setMid(mid);
        // ==================进球数===============
        log.info("准备发送赛果=======" + jsonArray);
        ResultAction.instance().push("detail", Result.success().addData(
                Result.createMap("mid", match.getMid(), "list", jsonArray)
        ));
        log.info("发送赛果结束,mid:" + match.getMid());
        this.goalsNum(match, jsonArray);
    }



    /**
     * 给管理员发送邮件
     * @param match
     */
    private void sendEmail(CrownMatch match) {
        // 开赛时间(美东)转系统时间
        long matchTime = DateUtil.timeZoneConvertSys("America/New_York", match.getDateTimestamp());
        long l = (System.currentTimeMillis() - matchTime) / 1000;
        // 超过赛事时间2小时 4小时 6小时发送邮件
        if ((l >= 3600 * 2 && l <= 3600 * 2.5) || (l >= 3600 * 4 && l <= 3600 * 4.5) || (l >= 3600 * 6 && l <= 3600 * 6.5)) {
            log.info("赛果爬取失败发送邮件。开赛时间已过：" + l + "s");
            sysParamService.sendEmail("3412995626@qq.com","赛果获取不到",
                    "mid：" + match.getMid() + "。开赛时间已过：" + l + "s" + "。位置：cr");
        }
    }



    /**
     * 请求皇冠并检验数据
     *
     * @param match
     * @param crownConfig
     * @return
     */
    private JSONArray getData(CrownMatch match, CrownConfig crownConfig) {
        // 66.133.86.54/app/member/account/result/FT_result_new.php?uid=tia85gppm22923423l237718&gtype=FT&game_id=4089557&langx=en-us
        String tailUrl = "/app/member/account/result/FT_result_new.php?uid=" + crownConfig.getUid()
                + "&gtype=FT&game_id=" + match.getMid() + "&langx=" + CrownConstant.LANGX;
      String body = crownConfigService.getCrownData(tailUrl, crownConfig, CrownConstant.RE_TRY_TIMES);
//        String body = "var gdata = Array('4591511','2020-12-22','03:00p','FRA 2','Grenoble Foot 38','Troyes AC','20752','20751','Y','false','0','0','','','','H','0','0','','','','N','','H','Cancelled','DL','Cancelled','DL','0','0','','','Cancelled','DL','Cancelled','DL','','N','0','0','','','Invisible Match','DL','1','0','','','Invisible Match','DL','','H','','N','Invisible Match','DL','1','0','','','Invisible Match','DL','Cancelled','DL','Cancelled','DL','2','0','','','Invisible Match','DL','0','0','','','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Cancelled','DL','Cancelled','DL','Invisible Match','DL','Invisible Match','DL','','Home','','Home','Invisible Match','DL','Cancelled','DL','Cancelled','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Invisible Match','DL','Cancelled','DL','Cancelled','DL','','5','','2','Invisible Match','DL','Cancelled','DL','Cancelled','DL','','','');";
        // 检测账号被登出
        if (crownConfigService.checkLogout(body, crownConfig)) {
            return null;
        }
        // body是空，监测到皇冠维护都return
        if (Strings.isBlank(body)) {
            log.error("爬取赛果失败，body为空");
            return null;
        } else if (crownConfigService.checkMaintain(body, crownConfig)) {
            return null;
        }
        // 解析body
        Matcher m = MATCH_COMPILE.matcher(body);
        // 如果获取不到gdata= return
        if (!m.find()) {
            log.error("赛果数据中没有gdata=,mid:" + match.getMid());
            return null;
        }
        log.info("开始解析足球赛事赛果, mid:" + match.getMid());
        String group = m.group();
        JSONArray jsonArray = JSONArray.parseArray("[" + group.substring(14, group.length() - 2) + "]");
        // 如果赛事没有结束 return
        if ("N".equals(jsonArray.getString(8))) {
            log.error("赛果数据中结束状态为N,mid:" + match.getMid());
            return null;
        }
        // 校验jsonArray与match的主客队名是否相同
        if (!jsonArray.getString(4).trim().equals(match.getHome().trim()) || !jsonArray.getString(5).trim().equals(match.getCustom().trim())) {
            log.error("赛果数据中主客队名与数据库中主客队名不相同,mid:" + match.getMid());
            return null;
        }
        return jsonArray;
    }


    /**
     * key: 赛事异常信息
     * value: 赛事阶段标记 & 文字
     */
    private Map<Integer, String> tagMap = Result.createHashMap(
            74, "NO4",
            68, "NO8"
    );


    /**
     * 进球数爬取
     *
     * @param match     CrownMatch对象。目前对象中的主客队比分属性，在结算中有用到
     * @param jsonArray 爬取的数据源
     */
    @Aop(TransAop.REPEATABLE_READ)
    private void goalsNum(CrownMatch match, JSONArray jsonArray) {
        String hInBall, cInBall, exInfo;
        // 赛事异常flag
        boolean matchExFlag = false;
        for (Map.Entry<Integer, String> entry : tagMap.entrySet()) {
            Integer key = entry.getKey();
            exInfo = jsonArray.getString(key);
            hInBall = jsonArray.getString(key - 2);
            cInBall = jsonArray.getString(key - 1);
            String stage = entry.getValue();
            // 如果异常信息不为空，说明赛事出现异常，取异常信息赋值给比分
            if ((Strings.isNotBlank(exInfo))) {
                hInBall = exInfo;
                cInBall = exInfo;
                // 赛事腰斩不算赛事异常
                if (CrownConstant.CUT.equals(exInfo)) {
                    match.setIsCut(true);
                } else {
                    matchExFlag = true;
                }
            }
            // 校验赛果，如果比分出现‘-’或者空 则 return
            if ("-".equals(hInBall) || "-".equals(cInBall) || Strings.isBlank(hInBall) || Strings.isBlank(cInBall)) {
                return;
            }
            // 正常赋值赛果
            if ("NO4".equals(stage)) {
                match.setHInBallHalf(hInBall);
                match.setCInBallHalf(cInBall);
            } else if ("NO8".equals(stage)) {
                match.setStage(matchExFlag ? CrownConstant.OTHER : CrownConstant.FINISHED);
                match.setHInBallFull(hInBall);
                match.setCInBallFull(cInBall);
            }
            // 更新赛果
            matchService.update(match);
        }
    }
}
